package com.twq.types.othertype

import com.twq.types.abstracttype.{Animal, Cow, Food}

/**
 * Created by tangweiqun on 2017/12/6.
 */
object PathDependentType {
  def main(args: Array[String]): Unit = {
    //1、farm.barm.cow.SuitableFood就是一个路径依赖类型， cow就是一个路径，
    // 这个路径可以是很多，比如farm.barn.bessy，其中farm、barn、bessy都是对象

    //路径依赖类型的类型是依赖路径的，路径不一样则类型也不一样
    val cow = new Cow
    val lassie = new Dog
    //lassie eat (new cow.SuitableFood)

    //2、两只不同狗的SuitableFood的类型实际上是一样的
    val bootsie = new Dog
    lassie eat (new bootsie.SuitableFood)

    //3、嵌套类中的路径依赖对象
    val o1 = new Outer
    val o2 = new Outer
    new o1.Inner

    //o1.y和o2.y的类型是不一样的
    o1.foo(o1.y) //因为参数是path-dependent type，所以必须传入相同对象的o1实例给参数
    //o1.foo(o2.y)
    o2.foo(o2.y)
    //o2.foo(o1.y)

    //4、如果想传入的类型和路径无关，那么我们使用类型投影
    o1.bar(o2.y)
  }
}

class DogFood extends Food

class Dog extends Animal {
  type SuitableFood = DogFood

  override def eat(food: DogFood) = {}
}

class Outer {

  class Inner

  def y = new Inner {}

  def foo(x: this.Inner) = null

  //2、相对来说 # 就比 . 的限制宽松了很多，不管哪个对象的实例都可以作为参数
  //Outer#Inner是类型投影(type projection)
  def bar(x: Outer#Inner) = null
}
